This notebooks will help me talk through a bit of material regarding spatial data, with some introduction to spatial joins.

Key topics for today:

Packages

Standards:

library(knitr)
library(tidyverse)
library(janitor)
library(lubridate) # because we will probably see some dates
library(here) # a package I haven't taught you about before that doesn't do much, but ....
library(rnaturalearth)
library(WDI)
library(tigris)
library(rgdal)
library(sp)

Some additional packages focused on today’s work:

library(sf) # working with simple features - geospatial
library(tmap)
library(tidycensus)

Informational resources

Using the Neighborhood Geospatial Data (using /data)

Our first data source comes from opendata.dc

https://opendata.dc.gov/datasets/DCGIS::dc-health-planning-neighborhoods/about

I will use the GeoJSON file. (Newer, not necessarily better, but … a single file. Not smaller, but … this one is not big.)

Data is easily readable

neigh=st_read(here("analysis", "DC_Health_Planning_Neighborhoods_joey.geojson")) %>% clean_names()
Reading layer `DC_Health_Planning_Neighborhoods' from data source 
  `/Users/sarahkohls/Desktop/College Classes/Intro to Data Science/DS241-Class-Project/analysis/DC_Health_Planning_Neighborhoods_joey.geojson' 
  using driver `GeoJSON'
Simple feature collection with 51 features and 8 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -77.11976 ymin: 38.79165 xmax: -76.9094 ymax: 38.99556
Geodetic CRS:  WGS 84
class(neigh)
[1] "sf"         "data.frame"
plot(neigh)

Reminder - Joins

df1=tibble(fruit=c("apple","banana","cherry"),cost=c(1.5,1.2,2.25))
df2=tibble(fruit=c("apple","apple","cherry","lemon"),
           desert=c("pie","cobbler","cobbler","cheesecake"),
           cal=c(400,430,500,550))
df1
df2
left_join(df1,df2,by="fruit")

Investigating joining spatial and non-spatial data

Covid case information is available from opendatadc:

https://opendata.dc.gov/datasets/DCGIS::dc-covid-19-total-positive-cases-by-neighborhood/about

Read cases information:

df_c=read_csv(here("analysis"," DC_COVID-19_Total_Positive_Cases_by_Neighborhood_joey.csv")) %>% clean_names() 
Error: '/Users/sarahkohls/Desktop/College Classes/Intro to Data Science/DS241-Class-Project/analysis/ DC_COVID-19_Total_Positive_Cases_by_Neighborhood_joey.csv' does not exist.

Regular joining (of dataframes)

neigh2=left_join(neigh,df_cases,by=c("code")) 

tmap_mode("view")
tmap mode set to interactive viewing
tm_shape(neigh2) +tm_polygons("total_positives",alpha=.5)

Joining with other spatial data

Let’s get some data using tidycensus. Need an API key https://api.census.gov/data/key_signup.html



census_api_key("d44395e2fa101f82260fae6b845676d71f017b70")
To install your API key for use in future sessions, run this function with `install = TRUE`.
#what variables
v20 = load_variables(2018,"acs5")
# median_family_income="    B06011_001" 
# all "B00001_001"  
#black "B02009_001"

Get some data:

df_cencus=get_acs(geography = "tract",
                  variables=c("median_inc"="B06011_001",
                              "pop"="B01001_001",
                              "pop_black"="B02009_001"),
                  state="DC",geometry=TRUE,year=2018) 
Getting data from the 2014-2018 5-year ACS
Downloading feature geometry from the Census website.  To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
Using FIPS code '11' for state 'DC'
class(df_cencus)
[1] "sf"         "data.frame"
plot(df_cencus)

It’s in long format. Let’s make it wide.

df_cens=df_cencus %>% select(-moe) %>% spread(variable,estimate) 

tm_shape(df_cens) +tm_polygons("median_inc",alpha=.5)

  tm_shape(neigh2) +tm_borders(col="blue",lwd=5,alpha=.2)+
  tm_shape(df_cens) +tm_borders(col="red",lwd=1,alpha=.3)
```r
#<<<<<<< HEAD
#df_j=st_join(df_cens,neigh2)
#=======
#df_j=st_join(df_cens,neigh2,prepared=FALSE)
#>>>>>>> aaf01be5cf721819dd2df615aef7a1999bcec0c2

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuZGZfY2Vuc19hZGo9ZGZfY2VucyAlPiUgc3RfdHJhbnNmb3JtKDQzMjYpXG5gYGAifQ== -->

```r
df_cens_adj=df_cens %>% st_transform(4326)
df_j=st_join(df_cens_adj,neigh2,largest=TRUE)
Warning: attribute variables are assumed to be spatially constant throughout all geometries

Other order?:

```r
#<<<<<<< HEAD
##df_j_rev = st_join(neigh2,df_cens_adj,largest=TRUE)
#=======
#df_j_rev = st_join(neigh2,df_cens_adj,largest=TRUE)
#>>>>>>> aaf01be5cf721819dd2df615aef7a1999bcec0c2

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Since we want the geometry for the NEIGHBORHOODS, we need a to work a little harder:


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuZGYxPWRmX2ogJT4lIHNlbGVjdChtZWRpYW5faW5jLHBvcCxwb3BfYmxhY2ssb2JqZWN0aWQpICU+JVxuICBncm91cF9ieShvYmplY3RpZCkgJT4lXG4gIHN1bW1hcmlzZShwb3Bfbj1zdW0ocG9wKSxcbiAgICAgICAgICAgIHBvcF9ibGFja19uPXN1bShwb3BfYmxhY2spLCBcbiAgICAgICAgICAgIGFkal9tZWRpYW5faW5jb21lPXN1bShwb3AqbWVkaWFuX2luYykvcG9wX24pIFxuXG5wbG90KGRmMSlcbmBgYCJ9 -->

```r
df1=df_j %>% select(median_inc,pop,pop_black,objectid) %>%
  group_by(objectid) %>%
  summarise(pop_n=sum(pop),
            pop_black_n=sum(pop_black), 
            adj_median_income=sum(pop*median_inc)/pop_n) 

plot(df1)

#df2=left_join(neigh2,df1)

df2=left_join(neigh2,df1 %>% st_set_geometry(NULL))
Joining, by = "objectid"
df2=df2 %>% mutate(black_perc=pop_black_n/pop_n, covid_rate=total_positives/pop_n)
tm_shape(df2)+tm_polygons(c("adj_median_income","covid_rate","black_perc"))
```r
df2 %>% filter(objectid!=30) %>% tm_shape()+tm_polygons(c(\adj_median_income\,\covid_rate\,\black_perc\),alpha=.4)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->

#find where people ride bikes (bikes started in each 'district')

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuYmlrZV9kYXRhIDwtIHJlYWRfY3N2KFxcMjAyMjA5LWNhcGl0YWxiaWtlc2hhcmUtdHJpcGRhdGEuY3N2XFwpICU+JSBjbGVhbl9uYW1lcygpXG5gYGBcbmBgYCJ9 -->

```r
```r
bike_data <- read_csv(\202209-capitalbikeshare-tripdata.csv\) %>% clean_names()

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuYmlrZV9kYXRhX3NmIDwtIGJpa2VfZGF0YSAlPiVcbiAgbXV0YXRlX2F0KHZhcnMoc3RhcnRfbGF0LCBzdGFydF9sbmcpLCBhcy5udW1lcmljKSAlPiVcbiAgc3RfYXNfc2YoXG4gICAgY29vcmRzID0gYyhcXHN0YXJ0X2xhdFxcLCBcXHN0YXJ0X2xuZ1xcKSwgXG4gICAgYWdyID0gXFxjb25zdGFudFxcLFxuICAgIGNycyA9IFxcNDMyNlxcXG4gICkgJT4lXG4gIHNhbXBsZV9uKDEwMDApXG5gYGBcbmBgYCJ9 -->

```r
```r
bike_data_sf <- bike_data %>%
  mutate_at(vars(start_lat, start_lng), as.numeric) %>%
  st_as_sf(
    coords = c(\start_lat\, \start_lng\), 
    agr = \constant\,
    crs = \4326\
  ) %>%
  sample_n(1000)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc3RfY3JzKGJpa2VfZGF0YV9zZilcbnN0X2NycyhuZWlnaDIpXG5gYGBcbmBgYCJ9 -->

```r
```r
st_crs(bike_data_sf)
st_crs(neigh2)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc3RfY3JzKGJpa2VfZGF0YV9zZikgPC0gNDMyNlxuYGBgXG5gYGAifQ== -->

```r
```r
st_crs(bike_data_sf) <- 4326

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuYmlrZV9kYXRhX3NmXzEgPC0gYmlrZV9kYXRhX3NmICU+JVxuICBzZWxlY3QoZ2VvbWV0cnkpICU+JVxuICByZW5hbWUoZ2VvbV9wb2ludHMgPSBnZW9tZXRyeSlcblxubmVpZ2gyXzEgPC0gbmVpZ2gyICU+JVxuICBzZWxlY3QoZ2VvbWV0cnkpXG5gYGBcbmBgYCJ9 -->

```r
```r
bike_data_sf_1 <- bike_data_sf %>%
  select(geometry) %>%
  rename(geom_points = geometry)

neigh2_1 <- neigh2 %>%
  select(geometry)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->

  

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZGZfcGx6ID0gc3Rfam9pbihiaWtlX2RhdGFfc2ZfMSwgbmVpZ2gyXzEsIGpvaW4gPSBzdF93aXRoaW4pXG5cbiNkZl9iaWtlc19jb3VudCA8LSBjb3VudChhc190aWJibGUoZGZfcGx6KSwgKVxuYGBgXG5gYGAifQ== -->

```r
```r
df_plz = st_join(bike_data_sf_1, neigh2_1, join = st_within)

#df_bikes_count <- count(as_tibble(df_plz), )

```

https://dw-rowlands.github.io/Job_Density_and_Commutes/Job_Density_and_Commutes.html

https://walker-data.com/census-r/index.html

What other interesting questions - is peak in bike data actually people going to work or tourist? - are casual riders in the more touristy areas? open data dc, tourist data, reverse geo coding to find location of monuments :):

Question to answer: Is there a spatial patter driven associated with member/casual? - look on open data dc site - could be some data on tourist activity

LS0tCnRpdGxlOiAiUmVwbGFjZW1lbnQgQ2xhc3MgLSBDbGVhbmluZyB1cCBhbmQgU3BhdGlhbCBKb2lucyIKZGF0ZTogICIyMDIyLTExLTA5IgphdXRob3I6ICJDb2FjaCBTa3VmY2EiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgbm90ZWJvb2tzIHdpbGwgaGVscCBtZSB0YWxrIHRocm91Z2ggYSBiaXQgb2YgbWF0ZXJpYWwgcmVnYXJkaW5nICpzcGF0aWFsIGRhdGEqLCAKd2l0aCBzb21lIGludHJvZHVjdGlvbiB0byBgc3BhdGlhbCBqb2luc2AuCgpLZXkgdG9waWNzIGZvciB0b2RheToKCiogVXNpbmcgYHNmYCBwYWNrYWdlCiogVXNpbmcgYHRtYXBgIHBhY2thZ2UKKiBVc2luZyBgdGlkeWNlbnN1c2AgcGFja2FnZQoqIFJlbWluZGVyIG9uIGpvaW5zIChmb2N1czogbGVmdCBqb2luKQoqIE91ciBTcGF0aWFsIERhdGEKICAgKiBOZWlnaGJvcmhvb2RzCiAgICogSm9pbmluZyB3aXRoIG5vbi1zcGF0aWFsIGRhdGEKICAgKiBDZW5zdXMgZGF0YQogICAqIEpvaW5pbmcgd2l0aCBzcGF0aWFsIGRhdGEKKiBpZ25vcmUgaHRtbCBpbiBnaXQgIChpZiB0aW1lKQoKIyMgUGFja2FnZXMKClN0YW5kYXJkczoKCmBgYHtyfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGx1YnJpZGF0ZSkgIyBiZWNhdXNlIHdlIHdpbGwgcHJvYmFibHkgc2VlIHNvbWUgZGF0ZXMKbGlicmFyeShoZXJlKSAjIGEgcGFja2FnZSBJIGhhdmVuJ3QgdGF1Z2h0IHlvdSBhYm91dCBiZWZvcmUgdGhhdCBkb2Vzbid0IGRvIG11Y2gsIGJ1dCAuLi4uCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkKbGlicmFyeShXREkpCmxpYnJhcnkodGlncmlzKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KHNwKQpgYGAKClNvbWUgYWRkaXRpb25hbCBwYWNrYWdlcyBmb2N1c2VkIG9uIHRvZGF5J3Mgd29yazoKCmBgYHtyfQpsaWJyYXJ5KHNmKSAjIHdvcmtpbmcgd2l0aCBzaW1wbGUgZmVhdHVyZXMgLSBnZW9zcGF0aWFsCmxpYnJhcnkodG1hcCkKbGlicmFyeSh0aWR5Y2Vuc3VzKQoKYGBgCiMjIEluZm9ybWF0aW9uYWwgcmVzb3VyY2VzCgoqIEFuIG92ZXJhbGwgcmVzb3VyY2Ugb24gbWFwcGluZyBpbiBSOiBodHRwczovL2Jvb2tkb3duLm9yZy9uaWNvaGFobi9tYWtpbmdfbWFwc193aXRoX3I1L2RvY3MvaW50cm9kdWN0aW9uLmh0bWwKKiBBIHN0YXJ0aW5nIHBvaW50IHRvIGxlYXJuIGFib3V0IGBzZmA6ICBodHRwczovL3Itc3BhdGlhbC5naXRodWIuaW8vc2YvYXJ0aWNsZXMvCiogR2V0dGluZyBzdGFydGVkIHdpdGggYHRtYXBgOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdG1hcC92aWduZXR0ZXMvdG1hcC1nZXRzdGFydGVkLmh0bWwKKiBUaGUgYHRpZHljZW5zdXNgIHBhY2thZ2U6IGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvaW5kZXguaHRtbAoqIFRoZSBib29rIG9uIGB0aWR5Y2Vuc3VzYCA6IGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL2NlbnN1cy1yL2luZGV4Lmh0bWwKCgojIyBVc2luZyB0aGUgTmVpZ2hib3Job29kIEdlb3NwYXRpYWwgRGF0YSAodXNpbmcgL2RhdGEpCgoKT3VyIGZpcnN0IGRhdGEgc291cmNlIGNvbWVzIGZyb20gb3BlbmRhdGEuZGMKCmh0dHBzOi8vb3BlbmRhdGEuZGMuZ292L2RhdGFzZXRzL0RDR0lTOjpkYy1oZWFsdGgtcGxhbm5pbmctbmVpZ2hib3Job29kcy9hYm91dAoKCkkgd2lsbCB1c2UgdGhlIEdlb0pTT04gZmlsZS4gIChOZXdlciwgbm90IG5lY2Vzc2FyaWx5IGJldHRlciwgYnV0IC4uLiBhIHNpbmdsZSBmaWxlLiAgTm90IHNtYWxsZXIsIGJ1dCAuLi4gdGhpcyBvbmUgaXMgbm90IGJpZy4pICAKCgoKCkRhdGEgaXMgZWFzaWx5IHJlYWRhYmxlIApgYGB7cn0KbmVpZ2g9c3RfcmVhZChoZXJlKCJhbmFseXNpcyIsICJEQ19IZWFsdGhfUGxhbm5pbmdfTmVpZ2hib3Job29kc19qb2V5Lmdlb2pzb24iKSkgJT4lIGNsZWFuX25hbWVzKCkKY2xhc3MobmVpZ2gpCmBgYAoKYGBge3J9CnBsb3QobmVpZ2gpCmBgYAoKCgojIyBSZW1pbmRlciAtIEpvaW5zCgpgYGB7cn0KZGYxPXRpYmJsZShmcnVpdD1jKCJhcHBsZSIsImJhbmFuYSIsImNoZXJyeSIpLGNvc3Q9YygxLjUsMS4yLDIuMjUpKQpkZjI9dGliYmxlKGZydWl0PWMoImFwcGxlIiwiYXBwbGUiLCJjaGVycnkiLCJsZW1vbiIpLAogICAgICAgICAgIGRlc2VydD1jKCJwaWUiLCJjb2JibGVyIiwiY29iYmxlciIsImNoZWVzZWNha2UiKSwKICAgICAgICAgICBjYWw9Yyg0MDAsNDMwLDUwMCw1NTApKQpkZjEKYGBgCmBgYHtyfQpkZjIKYGBgCmBgYHtyfQpsZWZ0X2pvaW4oZGYxLGRmMixieT0iZnJ1aXQiKQpgYGAKCiMjIEludmVzdGlnYXRpbmcgam9pbmluZyBzcGF0aWFsIGFuZCBub24tc3BhdGlhbCBkYXRhCgoKQ292aWQgY2FzZSBpbmZvcm1hdGlvbiBpcyBhdmFpbGFibGUgZnJvbSBvcGVuZGF0YWRjOgoKaHR0cHM6Ly9vcGVuZGF0YS5kYy5nb3YvZGF0YXNldHMvRENHSVM6OmRjLWNvdmlkLTE5LXRvdGFsLXBvc2l0aXZlLWNhc2VzLWJ5LW5laWdoYm9yaG9vZC9hYm91dAoKUmVhZCBjYXNlcyBpbmZvcm1hdGlvbjoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRmX2M9cmVhZF9jc3YoaGVyZSgiYW5hbHlzaXMiLCIgRENfQ09WSUQtMTlfVG90YWxfUG9zaXRpdmVfQ2FzZXNfYnlfTmVpZ2hib3Job29kX2pvZXkuY3N2IikpICU+JSBjbGVhbl9uYW1lcygpIAoKZGZfY2FzZXM9ZGZfYyAlPiUKICBmaWx0ZXIoYXNfZGF0ZShkYXRlX3JlcG9ydGVkKSA9PSAiMjAyMi0wMi0yMiIpICU+JSAKICBzZXBhcmF0ZShuZWlnaGJvcmhvb2QsaW50bz1jKCJjb2RlIiwibmFtZSIpLHNlcCA9ICI6IikgJT4lCiAgbXV0YXRlKGNvZGU9Y2FzZV93aGVuKAogICAgY29kZT09Ik4zNSIgfiJOMCIsCiAgICBUUlVFIH4gY29kZQogICkpICU+JQogIHNlbGVjdCgtb2JqZWN0aWQsLWRhdGVfcmVwb3J0ZWQpCgoKYGBgCgoKIyMgUmVndWxhciBqb2luaW5nIChvZiBkYXRhZnJhbWVzKQoKYGBge3J9Cm5laWdoMj1sZWZ0X2pvaW4obmVpZ2gsZGZfY2FzZXMsYnk9YygiY29kZSIpKSAKCnRtYXBfbW9kZSgidmlldyIpCgp0bV9zaGFwZShuZWlnaDIpICt0bV9wb2x5Z29ucygidG90YWxfcG9zaXRpdmVzIixhbHBoYT0uNSkKYGBgCgoKIyMgSm9pbmluZyB3aXRoIG90aGVyIHNwYXRpYWwgZGF0YQoKTGV0J3MgZ2V0IHNvbWUgZGF0YSB1c2luZyBgdGlkeWNlbnN1c2AuICBOZWVkIGFuIEFQSSBrZXkgICBodHRwczovL2FwaS5jZW5zdXMuZ292L2RhdGEva2V5X3NpZ251cC5odG1sCgoKYGBge3J9CgoKY2Vuc3VzX2FwaV9rZXkoImQ0NDM5NWUyZmExMDFmODIyNjBmYWU2Yjg0NTY3NmQ3MWYwMTdiNzAiKQoKI3doYXQgdmFyaWFibGVzCnYyMCA9IGxvYWRfdmFyaWFibGVzKDIwMTgsImFjczUiKQojIG1lZGlhbl9mYW1pbHlfaW5jb21lPSIJQjA2MDExXzAwMSIgCiMgYWxsICJCMDAwMDFfMDAxIgkKI2JsYWNrICJCMDIwMDlfMDAxIgpgYGAKCgpHZXQgc29tZSBkYXRhOgoKYGBge3J9CmRmX2NlbmN1cz1nZXRfYWNzKGdlb2dyYXBoeSA9ICJ0cmFjdCIsCiAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcz1jKCJtZWRpYW5faW5jIj0iQjA2MDExXzAwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3AiPSJCMDEwMDFfMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvcF9ibGFjayI9IkIwMjAwOV8wMDEiKSwKICAgICAgICAgICAgICAgICAgc3RhdGU9IkRDIixnZW9tZXRyeT1UUlVFLHllYXI9MjAxOCkgCmBgYAoKYGBge3J9CmNsYXNzKGRmX2NlbmN1cykKcGxvdChkZl9jZW5jdXMpCmBgYApJdCdzIGluIGxvbmcgZm9ybWF0LiAgTGV0J3MgbWFrZSBpdCB3aWRlLgpgYGB7cn0KZGZfY2Vucz1kZl9jZW5jdXMgJT4lIHNlbGVjdCgtbW9lKSAlPiUgc3ByZWFkKHZhcmlhYmxlLGVzdGltYXRlKSAKCnRtX3NoYXBlKGRmX2NlbnMpICt0bV9wb2x5Z29ucygibWVkaWFuX2luYyIsYWxwaGE9LjUpCmBgYAoKCmBgYHtyfQoKICB0bV9zaGFwZShuZWlnaDIpICt0bV9ib3JkZXJzKGNvbD0iYmx1ZSIsbHdkPTUsYWxwaGE9LjIpKwogIHRtX3NoYXBlKGRmX2NlbnMpICt0bV9ib3JkZXJzKGNvbD0icmVkIixsd2Q9MSxhbHBoYT0uMykKYGBgCgoKCmBgYHtyfQojPDw8PDw8PCBIRUFECiNkZl9qPXN0X2pvaW4oZGZfY2VucyxuZWlnaDIpCiM9PT09PT09CiNkZl9qPXN0X2pvaW4oZGZfY2VucyxuZWlnaDIscHJlcGFyZWQ9RkFMU0UpCiM+Pj4+Pj4+IGFhZjAxYmU1Y2Y3MjE4MTlkZDJkZjYxNWFlZjdhMTk5OWJjZWMwYzIKYGBgCgpgYGB7cn0KZGZfY2Vuc19hZGo9ZGZfY2VucyAlPiUgc3RfdHJhbnNmb3JtKDQzMjYpCmBgYAoKYGBge3J9CmRmX2o9c3Rfam9pbihkZl9jZW5zX2FkaixuZWlnaDIsbGFyZ2VzdD1UUlVFKQpgYGAKT3RoZXIgb3JkZXI/OgoKYGBge3J9CiM8PDw8PDw8IEhFQUQKIyNkZl9qX3JldiA9IHN0X2pvaW4obmVpZ2gyLGRmX2NlbnNfYWRqLGxhcmdlc3Q9VFJVRSkKIz09PT09PT0KI2RmX2pfcmV2ID0gc3Rfam9pbihuZWlnaDIsZGZfY2Vuc19hZGosbGFyZ2VzdD1UUlVFKQojPj4+Pj4+PiBhYWYwMWJlNWNmNzIxODE5ZGQyZGY2MTVhZWY3YTE5OTliY2VjMGMyCmBgYAoKU2luY2Ugd2Ugd2FudCB0aGUgZ2VvbWV0cnkgZm9yIHRoZSBORUlHSEJPUkhPT0RTLCB3ZSBuZWVkIGEgdG8gd29yayBhIGxpdHRsZSBoYXJkZXI6CgpgYGB7cn0KZGYxPWRmX2ogJT4lIHNlbGVjdChtZWRpYW5faW5jLHBvcCxwb3BfYmxhY2ssb2JqZWN0aWQpICU+JQogIGdyb3VwX2J5KG9iamVjdGlkKSAlPiUKICBzdW1tYXJpc2UocG9wX249c3VtKHBvcCksCiAgICAgICAgICAgIHBvcF9ibGFja19uPXN1bShwb3BfYmxhY2spLCAKICAgICAgICAgICAgYWRqX21lZGlhbl9pbmNvbWU9c3VtKHBvcCptZWRpYW5faW5jKS9wb3BfbikgCgpwbG90KGRmMSkKYGBgCgpgYGB7cn0KI2RmMj1sZWZ0X2pvaW4obmVpZ2gyLGRmMSkKCmRmMj1sZWZ0X2pvaW4obmVpZ2gyLGRmMSAlPiUgc3Rfc2V0X2dlb21ldHJ5KE5VTEwpKQoKYGBgCgpgYGB7cn0KZGYyPWRmMiAlPiUgbXV0YXRlKGJsYWNrX3BlcmM9cG9wX2JsYWNrX24vcG9wX24sIGNvdmlkX3JhdGU9dG90YWxfcG9zaXRpdmVzL3BvcF9uKQp0bV9zaGFwZShkZjIpK3RtX3BvbHlnb25zKGMoImFkal9tZWRpYW5faW5jb21lIiwiY292aWRfcmF0ZSIsImJsYWNrX3BlcmMiKSkKYGBgCgoKCmBgYHtyfQpkZjIgJT4lIGZpbHRlcihvYmplY3RpZCE9MzApICU+JSB0bV9zaGFwZSgpK3RtX3BvbHlnb25zKGMoImFkal9tZWRpYW5faW5jb21lIiwiY292aWRfcmF0ZSIsImJsYWNrX3BlcmMiKSxhbHBoYT0uNCkKYGBgCiNmaW5kIHdoZXJlIHBlb3BsZSByaWRlIGJpa2VzIChiaWtlcyBzdGFydGVkIGluIGVhY2ggJ2Rpc3RyaWN0JykKYGBge3J9CmJpa2VfZGF0YSA8LSByZWFkX2NzdigiMjAyMjA5LWNhcGl0YWxiaWtlc2hhcmUtdHJpcGRhdGEuY3N2IikgJT4lIGNsZWFuX25hbWVzKCkKYGBgCgpgYGB7cn0KYmlrZV9kYXRhX3NmIDwtIGJpa2VfZGF0YSAlPiUKICBtdXRhdGVfYXQodmFycyhzdGFydF9sYXQsIHN0YXJ0X2xuZyksIGFzLm51bWVyaWMpICU+JQogIHN0X2FzX3NmKAogICAgY29vcmRzID0gYygic3RhcnRfbGF0IiwgInN0YXJ0X2xuZyIpLCAKICAgIGFnciA9ICJjb25zdGFudCIsCiAgICBjcnMgPSAiNDMyNiIKICApICU+JQogIHNhbXBsZV9uKDEwMDApCmBgYAoKYGBge3J9CnN0X2NycyhiaWtlX2RhdGFfc2YpCnN0X2NycyhuZWlnaDIpCmBgYAoKYGBge3J9CnN0X2NycyhiaWtlX2RhdGFfc2YpIDwtIDQzMjYKYGBgCgpgYGB7cn0KYmlrZV9kYXRhX3NmXzEgPC0gYmlrZV9kYXRhX3NmICU+JQogIHNlbGVjdChnZW9tZXRyeSkgJT4lCiAgcmVuYW1lKGdlb21fcG9pbnRzID0gZ2VvbWV0cnkpCgpuZWlnaDJfMSA8LSBuZWlnaDIgJT4lCiAgc2VsZWN0KGdlb21ldHJ5KQpgYGAKICAKYGBge3J9CmRmX3BseiA9IHN0X2pvaW4oYmlrZV9kYXRhX3NmXzEsIG5laWdoMl8xLCBqb2luID0gc3Rfd2l0aGluKQoKI2RmX2Jpa2VzX2NvdW50IDwtIGNvdW50KGFzX3RpYmJsZShkZl9wbHopLCApCmBgYAoKCmh0dHBzOi8vZHctcm93bGFuZHMuZ2l0aHViLmlvL0pvYl9EZW5zaXR5X2FuZF9Db21tdXRlcy9Kb2JfRGVuc2l0eV9hbmRfQ29tbXV0ZXMuaHRtbAoKaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vY2Vuc3VzLXIvaW5kZXguaHRtbAoKCldoYXQgb3RoZXIgaW50ZXJlc3RpbmcgcXVlc3Rpb25zCi0gaXMgcGVhayBpbiBiaWtlIGRhdGEgYWN0dWFsbHkgcGVvcGxlIGdvaW5nIHRvIHdvcmsgb3IgdG91cmlzdD8KLSBhcmUgY2FzdWFsIHJpZGVycyBpbiB0aGUgbW9yZSB0b3VyaXN0eSBhcmVhcz8Kb3BlbiBkYXRhIGRjLCB0b3VyaXN0IGRhdGEsIHJldmVyc2UgZ2VvIGNvZGluZyB0byBmaW5kIGxvY2F0aW9uIG9mIG1vbnVtZW50cyA6KToKClF1ZXN0aW9uIHRvIGFuc3dlcjoKSXMgdGhlcmUgYSBzcGF0aWFsIHBhdHRlciBkcml2ZW4gYXNzb2NpYXRlZCB3aXRoIG1lbWJlci9jYXN1YWw/Ci0gbG9vayBvbiBvcGVuIGRhdGEgZGMgc2l0ZQotIGNvdWxkIGJlIHNvbWUgZGF0YSBvbiB0b3VyaXN0IGFjdGl2aXR5Cgo=